-
Notifications
You must be signed in to change notification settings - Fork 391
[HW] Enhance FlattenModules pass with configurable inlining heuristics #9224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
2d14fe9 to
f3e4ccf
Compare
f3e4ccf to
c921ca7
Compare
seldridge
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
I didn't review the inner sym / hierarchical path update logic in much detail, though. I realize this was probably the most important thing to review. However, the tests are doing the right thing!
| Option<"smallThreshold", "small-threshold", "unsigned", "8", | ||
| "Maximum number of operations for a module to be considered small">, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Gating this behind --inline-small-threshold would be more obvious to me as a user.
| "Allow inlining of modules that contain state (seq.firreg operations)">, | ||
| Option<"inlineAll", "inline-all", "bool", "true", | ||
| "Inline all private modules regardless of heuristics (default behavior)"> | ||
| ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe prefixing these with --hw would be good. I've grown to liking having any option that is only for specific dialects is useful to indicate which dialect it works on. E.g., --dedup-classes in firtool would be better as --firrtl-dedup-classes. The same thing holds here, too.
| InnerSymbolNamespace *ns, HWModuleOp parentModule, | ||
| HWModuleOp sourceModule, | ||
| DenseMap<StringAttr, StringAttr> *symMapping, | ||
| mlir::AttrTypeReplacer *replacer, HierPathTable *pathsTable, | ||
| hw::InnerRefAttr instanceRef) | ||
| : InlinerInterface(context), prefix(prefix), ns(ns), | ||
| parentModule(parentModule), sourceModule(sourceModule), | ||
| symMapping(symMapping), replacer(replacer), pathsTable(pathsTable), | ||
| instanceRef(instanceRef) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This constructor may be unnecessary if you use struct initialization. E.g., PrefixingInliner{a, b, c}. I don't know if there's any utility in adding a one-to-one constructor here as opposed to the {} one.
| bool isEmpty = bodySize == 1; | ||
| bool hasNoOutputs = module.getNumOutputPorts() == 0; | ||
| bool hasOneUse = instanceNode->getNumUses() == 1; | ||
| bool hasState = !module.getOps<seq::FirRegOp>().empty(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about memories or other kinds of state?
| hw.module @TestSingleUse(in %x: i4, out y: i4) { | ||
| // NONE-NEXT: hw.instance "small" @SmallModule | ||
| // SINGLE-NEXT: %[[V0:.+]] = comb.add %x, %x | ||
| // SINGLE-NEXT: hw.output %[[V0]] | ||
| %0 = hw.instance "small" @SmallModule(a: %x: i4) -> (b: i4) | ||
| hw.output %0 : i4 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this may want to use a @LargeModule to definitely avoid this getting inlined with the small option. I.e., there could be a bug where small inlining is turned on and it would be good if this was test was not susceptible to that.
| hw.module private @TinyModule(in %a: i4, out b: i4) { | ||
| %0 = comb.add %a, %a : i4 | ||
| hw.output %0 : i4 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: This is just @SmallModule. Though, going off of the comment above, I think you want small to be "large" and tiny to be "small".
| // Test that public modules are not inlined | ||
| // CHECK-LABEL: hw.module @DontInlinePublic | ||
| hw.module @DontInlinePublic(in %x: i4, out y: i4) { | ||
| // CHECK-NEXT: hw.instance "pub" @PublicModule | ||
| %0 = hw.instance "pub" @PublicModule(a: %x: i4) -> (b: i4) | ||
| hw.output %0 : i4 | ||
| } | ||
| // CHECK: hw.module @PublicModule | ||
| hw.module @PublicModule(in %a: i4, out b: i4) { | ||
| %0 = comb.add %a, %a : i4 | ||
| hw.output %0 : i4 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside to think about: we could inline these still, just we can't delete them.
| // CHECK-NOT: hw.instance | ||
| // CHECK-NEXT: %[[V0:.+]] = comb.add %x, %x | ||
| // CHECK-NEXT: %[[W0:.+]] = hw.wire %[[V0]] sym @[[SYM:wire_op]] | ||
| // CHECK-NEXT: sv.verbatim "ref to {{[{][{]}}0{{[}][}]}}" {symbols = [#hw.innerNameRef<@InlineWithInnerRef::@[[SYM]]>]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mega-nit: There is only this one verbatim and the test could avoid the {{{{{}}}}}} shenanigans with just:
CHECK-NEXT: sv.verbatim {{.*}} {symbols = ...}
Or:
CHECK-NEXT: sv.verbatim
CHECK-SAME: {symbols = [#hw.innerNameRef<@InlineWithInnerRef::@[[SYM]]>]}
Ditto throughout.
| hw.module @InlineWithInnerRef(in %x: i4, out y: i4) { | ||
| // CHECK-NOT: hw.instance | ||
| // CHECK-NEXT: %[[V0:.+]] = comb.add %x, %x | ||
| // CHECK-NEXT: %[[W0:.+]] = hw.wire %[[V0]] sym @[[SYM:wire_op]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: there isn't any renaming here, so capturing this into SYM doesn't serve a purpose. The test probably does want to not capture wire_op exactly and should be .+ or an alpha-numeric capture. It's probably best to just use @wire_op directly if the expectation is this that this will be preserved exactly.
This PR enhances the existing
--hw-flatten-modulespass with configurable heuristics, hierarchical path support, and module NLA protection for fine-grained control over module inlining.The FlattenModules pass now supports:
InnerSymbolNamespaceto avoid conflictsInlining Heuristics (7 new options)
This PR also adds new lit tests for testing these enhancements.